/*
 * @Author: linxun 
 * @Date: 2021-05-21 14:59:14 
 * @Last Modified by: linxun
 * @Last Modified time: 2021-07-15 11:45:45
 * @Description: 图片查看器
 */

import React, { useEffect, useState } from 'react';
import { Modal, Button, Collapse, Descriptions } from 'antd';
import { LeftOutlined, RightOutlined } from '@ant-design/icons';
import moment from 'moment';
import { TIMEFORMAT } from '@/utils/const';
import useKeyPress from '@/utils/useKeyPress';
import { hex2Rgba } from '../util';
import styles from './ImageViewer.less';
import type { ImgProps, ImgLabelShapes } from './SamplesImages';

const { Panel } = Collapse;

// 需要canvas绘制标注的标注类型
const canvasTypes = ['object_detection', 'image_segmentation', 'ocr_detection'];

interface Props {
  imgs: ImgProps[];
  initIndex: number;
  visible: boolean;
  cancel: () => void;
  annotType: string;
  option: string;
  taskId?: string;
}

interface formatLabelInfoItemProps {
  label: string;
  color: string;
  points: labelPointsProps[];
}

interface labelPointsProps {
  x: number;
  y: number;
}

const ImagesViewer: React.FC<Props> = (props) => {
  const { imgs, initIndex, visible, cancel, annotType, option, taskId } = props;

  const [curImg, setCurImg] = useState<ImgProps | {}>({});
  const [curIndex, setCurIndex] = useState<number>(-1);
  const [imgLoaded, setImgLoaded] = useState<boolean>(false);
  const leftPress = useKeyPress('ArrowLeft');
  const rigthPress = useKeyPress('ArrowRight');

  const formatLabelInfo = (labelInfo: ImgLabelShapes[]) => {
    return labelInfo.map(item => {
      const { points, labelColor, labelName } = item;
      let result = [];
      for (let i = 0; i < points.length; i += 2) {
        result.push({
          x: Number(points[i]),
          y: Number(points[i + 1]),
        });
      }
      if (annotType !== 'image_segmentation') {
        // 物体检测、文本检测 矩形标注只有左上和右下两个点的坐标
        result = [result[0], { x: result[1].x, y: result[0].y }, result[1], { x: result[0].x, y: result[1].y }];
      }
      return {
        label: labelName,
        color: labelColor,
        points: result,
      };
    })
  };

  useEffect(() => {
    const img = new Image();
    // img.crossOrigin = 'anonymous';
    img.onload = function () {
      setImgLoaded(true);
      if (canvasTypes.includes(annotType) && taskId) {
        drawCanvas(img, formatLabelInfo((curImg as ImgProps).imageLabelShapes));
      }
    }
    img.src = (curImg as ImgProps).image?.url;
  }, [curImg]);

  useEffect(() => {
    setCurIndex(initIndex);
    setCurImg(imgs[initIndex] || {});
  }, [imgs, initIndex]);

  const preImg = () => {
    if (curIndex !== 0) {
      setImgLoaded(false);
      setCurImg(imgs[curIndex - 1]);
      setCurIndex(curIndex - 1);
    }
  };

  const nextImg = () => {
    if (curIndex !== imgs.length - 1) {
      setImgLoaded(false);
      setCurImg(imgs[curIndex + 1]);
      setCurIndex(curIndex + 1);
    }
  };

  useEffect(() => {
    if (visible) {
      leftPress && preImg();
      rigthPress && nextImg();
    }
  }, [visible, leftPress, rigthPress]);

  // const toAnnot = () => {
  //   console.log('去标注');
  // };

  const drawTextBG = (ctx: any, txt: string, font: string, x: number, y: number) => {
    ctx.save();
    ctx.font = font;
    ctx.textBaseline = 'bottom';
    ctx.fillStyle = 'rgba(255, 255, 255, .8)';
    const width = ctx.measureText(txt).width + 24;
    const height = parseInt(font, 10) + 10;
    ctx.fillRect(x, y - height, width, height);
    ctx.fillStyle = '#000';
    ctx.fillText(txt, x + 12, y);
    ctx.textAlign = 'center';
    ctx.restore();
  };

  const drawCanvas = (img: HTMLImageElement, labelInfo: formatLabelInfoItemProps[]) => {
    const canvas: any = document.getElementById('canvas');
    if (canvas) {
      const ctx = canvas.getContext('2d');
      canvas.width = img.width;
      canvas.height = img.height;
      ctx.drawImage(img, 0, 0);

      labelInfo.forEach(item => {
        const { points: curPoints, label, color } = item;
        // 物体检测、文本检测 矩形标注标签展示在左下角；图像分割 不规则图形标签展示在第一个点
        const tagPoint = curPoints[annotType !== 'image_segmentation' ? curPoints.length - 1 : 0];

        const drawLine = (x: number, y: number) => ctx.lineTo(x, y);
        // const drawArc = (x: number, y: number) => ctx.arc(x, y, 2, 0, 2 * Math.PI, true);

        // 绘制标签文案
        ctx.beginPath();
        const fontSize =
          img.width * img.height <= 1022 * 598
            ? 18
            : img.width * img.height <= 1320 * 780
              ? 24
              : img.width * img.height <= 1640 * 960
                ? 48
                : 96;
        drawTextBG(ctx, label, `${fontSize}px sans-serif`, tagPoint.x, tagPoint.y);
        ctx.fill();

        ctx.beginPath();
        ctx.fillStyle = hex2Rgba(color, 0.3);
        ctx.strokeStyle = color;
        ctx.lineWidth = 1;
        ctx.moveTo(curPoints[0]?.x, curPoints[0]?.y);
        // ctx.arc(curPoints[0]?.x, curPoints[0]?.y, 2, 0, 2 * Math.PI);
        for (let i = 1; i < curPoints.length; i++) {
          drawLine(curPoints[i]?.x, curPoints[i]?.y);
          // drawArc(curPoints[i]?.x, curPoints[i]?.y);
        }
        // 将标注闭合
        ctx.lineTo(curPoints[0]?.x, curPoints[0]?.y);
        ctx.stroke();
        ctx.fill();
        ctx.closePath();
      })
    }
  };

  const renderImgAndLabel = () => {
    switch (annotType) {
      case 'image_classification':  // 图像分类
        return (
          <div className={styles['img-box']}>
            {imgLoaded
              ? <div className={styles.img}><img src={(curImg as ImgProps).image?.url} /></div>
              : <div className={styles['img-loading']}>图片正在加载，请耐心等待</div>
            }
            {(curImg as ImgProps)?.imageLabelTags && (curImg as ImgProps)?.imageLabelTags.length ?
              <div className={styles['label-list']}>
                <div className={styles['label-list-title']}>识别结果：</div>
                <ul>
                  {(curImg as ImgProps).imageLabelTags.map(i => (
                    <li className={styles['label-list-li']} key={i.id}>{i.labelName}</li>
                  ))}
                </ul>
              </div> : null
            }
          </div>
        );
      case 'object_detection':  // 物体检测
      case 'image_segmentation':  // 图像分割
      case 'ocr_detection': // 文本检测
        return (
          <div className={styles['img-box']}>
            {imgLoaded
              ? (
                <div className={styles.img}>
                  {taskId ?
                    <canvas id='canvas'></canvas> :
                    <img src={(curImg as ImgProps).image?.url} />
                  }
                </div>
              ) : <div className={styles['img-loading']}>图片正在加载，请耐心等待</div>
            }
          </div>
        );
      case 'ocr_recognition': // 文本识别
        return (
          <div className={styles['ocr-box']}>
            <div className={`${styles['img-box']} ${styles['auto-width-img-box']}`}>
              {imgLoaded
                ? <div className={styles.img}><img src={(curImg as ImgProps).image?.url} /></div>
                : <div className={styles['img-loading']}>图片正在加载，请耐心等待</div>
              }
            </div>
            <div className={styles['txt-box']}>
              <pre>
                {(curImg as ImgProps).imageLabelTags?.[0]?.imageLabelTagAttrVals?.[0]?.value}
              </pre>
            </div>
          </div>
        );
      default:
        return (
          <div className={`${styles['img-box']} ${styles['auto-width-img-box']}`}>
            {imgLoaded
              ? <div className={styles.img}><img src={(curImg as ImgProps).image?.url} /></div>
              : <div className={styles['img-loading']}>图片正在加载，请耐心等待</div>
            }
          </div>
        );
    }
  };

  const getLabelText = () => {
    let result: string = '';
    let arr: any[] = canvasTypes.includes(annotType) ? (curImg as ImgProps).imageLabelShapes : (curImg as ImgProps).imageLabelTags;
    arr?.forEach(item => {
      result += `${item.labelName}；`;
    });
    return result;
  };

  return (
    <Modal
      title={(curImg as ImgProps).image?.path}
      visible={visible}
      onCancel={cancel}
      maskClosable={false}
      width='80%'
      style={{ maxWidth: 1200 }}
      footer={(
        <>
          {/* TODO: 已标注图片可直接跳转到标注界面，未标注图片只能先创建标注任务 */}
          {/* {option === '1' &&
            <Button type='primary' onClick={toAnnot} style={{ marginRight: 16 }}>去标注</Button>
          } */}
          <Button onClick={cancel}>关闭</Button>
        </>
      )}
      destroyOnClose
      afterClose={() => {
        setCurImg({});
        setImgLoaded(false);
      }}
    >
      <Collapse className={styles['img-info']}>
        <Panel header='图片信息' key={1}>
          <Descriptions bordered column={2}>
            <Descriptions.Item label='文件名称' span={2}>{(curImg as ImgProps).image?.path}</Descriptions.Item>
            <Descriptions.Item label='标注标签'>{getLabelText()}</Descriptions.Item>
            <Descriptions.Item label='标注状态'>{(curImg as ImgProps).isAnnotated ? '已标注' : '未标注'}</Descriptions.Item>
            <Descriptions.Item label='标注任务ID'>{(curImg as ImgProps).imageTaskId}</Descriptions.Item>
            <Descriptions.Item label='标注子任务ID'>{(curImg as ImgProps).imageSubTaskId}</Descriptions.Item>
            <Descriptions.Item label='标注员'>{(curImg as ImgProps).assignee}</Descriptions.Item>
            <Descriptions.Item label='文件格式'>{(curImg as ImgProps).image?.path?.split('.').pop()}</Descriptions.Item>
            <Descriptions.Item label='创建时间'>{moment((curImg as ImgProps).createdAt).format(TIMEFORMAT)}</Descriptions.Item>
            <Descriptions.Item label='标注更新日期'>{(curImg as ImgProps).isAnnotated ? moment((curImg as ImgProps).updatedAt).format(TIMEFORMAT) : ''}</Descriptions.Item>
          </Descriptions>
        </Panel>
      </Collapse>
      <div className={styles['modal-box']}>
        <LeftOutlined
          className={`${styles['toggle-icon']} ${curIndex === 0 ? styles['disabled-icon'] : ''}`}
          onClick={preImg}
        />
        {renderImgAndLabel()}
        <RightOutlined
          className={`${styles['toggle-icon']} ${curIndex === imgs.length - 1 ? styles['disabled-icon'] : ''}`}
          onClick={nextImg}
        />
      </div>
    </Modal>
  )
}

export default ImagesViewer;